;naskfunc

[FORMAT "WCOFF"]		;制作目标文件的模式
[INSTRSET "i486p"]		;使用到486为止的指令
[BITS 32]				;制作32位模式用的机器语言

;制作目标文件的信息
[FILE "naskfunc.nas"]	;源文件名信息
	GLOBAL _io_hlt,_write_mem8		;程序中包含的函数名
	GLOBAL _io_cli, _io_sti, _io_stihlt
	GLOBAL _io_in8, _io_in16, _io_in32
	GLOBAL _io_out8, _io_out16, _io_out32
	GLOBAL _io_load_eflags, _io_store_eflags
	GLOBAL _load_gdtr, _load_idtr
	GLOBAL _asm_inthandler21, _asm_inthandler27, _asm_inthandler2c, _asm_inthandler20
	GLOBAL _load_cr0,_store_cr0,_memtest_sub, _load_tr, _farjmp, _asm_cons_putchar
	GLOBAL _farcall, _asm_system_api, _start_app, _asm_inthandler0d, _asm_inthandler0c
	GLOBAL _asm_end_app
	
	EXTERN _inthandler20, _inthandler21, _inthandler27, _inthandler2c, _system_api
	EXTERN _inthandler0d, _inthandler0c

;以下是实际的函数
[SECTION .text]			;代码段,目标文件中写了这些之后再写程序

_io_hlt:	; void io_hlt(void);
	hlt
	ret

;在C语言调用汇编时，参数是放在栈中
_write_mem8:	;void write_mem8(int addr, int data);
	mov ecx,[esp+4]
	mov al,[esp+8]
	mov [ecx],al
	ret

_io_cli:	;void io_cli(void); ; 关闭所有可屏蔽中断
	cli
	ret
	
_io_sti:	;void io_sti(void) ; 打开所有可屏蔽中断
	sti
	ret

_io_stihlt:	;void io_stihlt(void);打开所有可屏蔽中断,并且处理器进入暂停状态
	sti
	hlt ;本指令是处理器“暂停”指令。功能： 使程序停止运行，处理器进入暂停状态，不执行任何操作，不影响标志
	ret
	
_io_in8:	;int io_in8(int port); ; 从port端口读入8位数据到AL中
	mov edx,[esp+4] ;port
	mov eax,0
	in al,dx
	ret

_io_in16:	;int io_in16(int port); ; 从port端口读入16位数据到AL中
	mov edx,[esp+4] ;port
	mov eax,0
	in ax,dx
	ret

_io_in32:	;int io_in32(int port); ; 从port端口读入32位数据到AL中
	mov edx,[esp+4] ;port
	in eax,dx
	ret

_io_out8: 	;void io_out8(int port, int data); ;将8位的data输出到port端口
	mov edx,[esp+4]	;port
	mov al,[esp+8]	;data
	out dx,al
	ret
	
_io_out16: 	;void io_out16(int port, int data); ;将16位的data输出到port端口
	mov edx,[esp+4]	;port
	mov eax,[esp+8]	;data
	out dx,ax
	ret

_io_out32: 	;void io_out32(int port, int data); ;将32位的data输出到port端口
	mov edx,[esp+4]	;port
	mov eax,[esp+8]	;data
	out dx,eax
	ret
	
_io_load_eflags:	;int io_load_eflags(void); ;将EFLAGS寄存器的内容返回
	pushfd	;将32位标志寄存器EFLAGS入栈
	pop eax	;标志寄存器中的值赋予eax
	ret
	
_io_store_eflags:	;void io_store_eflags(int eflags); ;将参数eflags的内容作为EFLAGS寄存器的值
	mov eax,[esp+4]	;eflags
	push eax	
	popfd 	;将栈顶双字弹出到EFLAGS中
	ret
	
_load_gdtr:		; void load_gdtr(int limit, int addr);	; 加载GDT	limit是GDT限长  addr是GDT基址
	mov ax,[esp+4]	; limit的低16bit  栈排列 FFFF0000 00002700
	mov [esp+6], ax ; FFFFFFFF 00002700
	lgdt [esp+6] ;GDTR48位寄存器，低16位放着GDT的有效字节数-1，高32位放着GDT的起始地址，那么从esp+6开始取值，恰好是0027 0000 FFFF，低16位是FFFF，高32位是0027 0000
	ret

_load_idtr:		; void load_idtr(int limit, int addr);	; 加载IDT	limit是IDT限长	addr是IDT基址
	mov ax,[esp+4]
	mov [esp+6], ax
	lidt [esp+6]
	ret

; ---------------------------------------------------------- 
;	   主PIC					从PIC
;	IRQ0	时钟			IRQ8	实时钟	
;	IRQ1	键盘			IRQ9	INTOAH
;	IRQ2	接连int		IRQ10	保留
;	IRQ3	串行口2		IRQ11	保留		
;	IEQ4	串行口1		IRQ12	PS2鼠标
;	IEQ5	并行口2		IRQ13	协处理器
;	IEQ6	软盘			IRQ14	硬盘	
;	IEQ7	并行口1		IRQ15	保留	
; ----------------------------------------------------------
_asm_inthandler20: ; IRQ0	时钟
	push es
	push ds
	pushad
	mov eax,esp
	push eax
	mov ax,ss
	mov ds,ax
	mov es,ax
	call _inthandler20 ;调用timer.c中的inthandler20
	pop eax
	popad
	pop ds
	pop es
	iretd
		
_asm_inthandler21:	; IRQ 1		键盘
	push es
	push ds
	pushad	;本指令将EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI这8个32位通用寄存器依次压入堆栈
	mov eax,esp
	push eax
	mov ax,ss
	mov ds,ax
	mov es,ax
	call _inthandler21
	pop eax
	popad
	pop ds
	pop es
	iretd	; 中断返回

_asm_inthandler27:	; IRQ 7		并行口1
	push es
	push ds
	pushad	;本指令将EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI这8个32位通用寄存器依次压入堆栈
	mov eax,esp
	push eax
	mov ax,ss
	mov ds,ax
	mov es,ax
	call _inthandler27
	pop eax
	popad
	pop ds
	pop es
	iretd	; 中断返回

_asm_inthandler2c:	; IRQ 12	PS2鼠标
	push es
	push ds
	pushad	;本指令将EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI这8个32位通用寄存器依次压入堆栈
	mov eax,esp
	push eax
	mov ax,ss
	mov ds,ax
	mov es,ax
	call _inthandler2c
	pop eax
	popad
	pop ds
	pop es
	iretd	; 中断返回

_asm_inthandler0c: ;void asm_inthandler0c(void);处理栈异常中断
	sti
	push es
	push ds
	pushad
	mov eax,esp
	push eax
	mov ax,ss
	mov ds,ax
	mov es,ax
	call _inthandler0c
	cmp eax,0
	jne _asm_end_app
	pop eax
	popad
	pop ds
	pop es
	add esp,4 ;在int 0x0c中也需要这句
	iretd
	
_asm_inthandler0d:	; 异常中断
	sti
	push es
	push ds
	pushad	;本指令将EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI这8个32位通用寄存器依次压入堆栈
	mov eax,esp
	push eax	;保存中断时的esp
	mov ax,ss
	mov ds,ax
	mov es,ax
	call _inthandler0d
	cmp eax,0
	jne _asm_end_app
	pop eax
	popad
	pop ds
	pop es
	add esp,4 ;在int 0x0d中需要这句
	iretd
	
_load_cr0: ; int load_cr0(void);
	mov eax,cr0
	ret

_store_cr0 ; void store_cr0(int cr0);
	mov eax,[esp+4]
	mov cr0,eax
	ret

_memtest_sub: ;unsigned int memtest_sub(unsigned int start, unsigned int end);
	push edi
	push esi
	push ebx
	mov esi, 0xaa55aa55 	; pat0 = 0xaa55aa55;
	mov edi, 0x55aa55aa	; pat1 = 0x55aa55aa;
	mov eax,[esp+12+4]	; i = start;
mts_loop:
	mov ebx,eax
	add ebx,0xffc	; p = i + 0xffc;
	mov edx,[ebx]	; old = *p;
	mov [ebx],esi	; *p = pat0;
	xor dword [ebx],0xffffffff	; *p ^= 0xffffffff;
	cmp edi,[ebx]			; if (*p != pat1) goto fin;
	jne mts_fin
	xor dword [ebx],0xffffffff	; *p ^= 0xffffffff;
	cmp esi,[ebx]			; if (*p != pat0) goto fin;
	jne mts_fin
	mov [ebx],edx		; *p = old;
	add eax,0x1000		; i += 0x1000;
	cmp eax,[esp+12+8]	; if (i <= end) goto mts_loop;
	
	jbe mts_loop
	pop ebx
	pop esi
	pop edi
	ret
mts_fin:
	mov [ebx],edx	; *p = old;
	pop ebx
	pop esi
	pop edi
	ret

_load_tr:	;void load_tr(int tr);
	ltr [esp+4]  ;tr
	ret
	
_farjmp: ;void farjmp(int eip, int cs);
	jmp far [esp+4] ;cs:ip
	ret
	
_farcall: ;void farcall(int eip,int cs);
	call far [esp+4] ;eip,cs
	ret
	
_asm_system_api: ;void asm_system_api(void);
	sti
	push ds

	push es
	pushad ;保存寄存器的值,eax-ecx-edx-ebx-esp-ebp-esi-edi
	pushad	;用于向system_api传值的push
	mov ax,ss
	mov ds,ax
	mov es,ax
	call _system_api
	cmp eax,0 ; 当eax不为0时程序结束
	jne _asm_end_app
	add esp,32
	popad
	pop es
	pop ds
	iretd
	
_asm_end_app:
	mov esp,[eax] ;eax为tss.esp0的地址
	mov dword [eax+4],0
	popad
	ret ;返回cmd_app

_start_app: ;void start_app(int eip, int cs, int esp, int ds, int *tss_esp0);
	pushad ;保存寄存器的值,eax-ecx-edx-ebx-esp-ebp-esi-edi
	mov eax,[esp+36] ;app用eip
	mov ecx,[esp+40] ;app用cs
	mov edx,[esp+44] ;app用esp
	mov ebx,[esp+48] ;app用ds/ss
	mov ebp,[esp+52] ;tss.esp0的地址
	mov [ebp],esp  ;操作系统用esp
	mov [ebp+4],ss ;操作系统用ss
	mov es,bx
	mov ds,bx
	mov fs,bx
	mov gs,bx
;下面调整栈，以免用retf跳转到应用程序
	or ecx,3	;应用程序代码段号
	or ebx,3	;应用程序数据段号
	push ebx	;应用程序ss
	push edx	;应用程序esp
	push ecx	;应用程序cs
	push eax	;应用程序eip
	retf
;应用程序结束后不会返回此处
